/**
 * 火花分镜服务
 * 负责将文本文档转换为分镜脚本
 */

import { AIService } from './aiService'
import { AIResult, AIErrorCode } from './types'
import {
  SparkStoryboardConfig,
  StoryboardGenerationRequest,
  GenerationProgress,
  VideoStyle,
  VIDEO_STYLE_LABELS
} from '../../types/sparkStoryboard'
import {
  StoryboardData,
  StoryboardScene,
  ShotType,
  CameraAngle,
  CameraMovement,
  LocationType,
  LightingCondition,
  AspectRatio,
  VideoResolution,
  generateId
} from '../../types/document'

/**
 * AI返回的场景数据接口
 */
interface AISceneData {
  title: string
  description: string
  shotType: string
  angle: string
  movement?: string
  duration: number
  order: number
}

/**
 * AI返回的场景列表接口
 */
interface AIScenesResponse {
  scenes: AISceneData[]
}

export class SparkStoryboardService {
  constructor(private aiService: AIService) {}

  /**
   * 生成分镜脚本
   */
  async generateStoryboard(
    request: StoryboardGenerationRequest,
    onProgress?: (progress: GenerationProgress) => void
  ): Promise<AIResult<StoryboardData>> {
    console.log('[火花分镜] 开始生成分镜脚本', {
      articleId: request.config.articleId,
      targetDuration: request.config.targetDuration,
      videoStyle: request.config.videoStyle
    })

    try {
      // 阶段1: 分析文章内容 (10%)
      onProgress?.({
        phase: 'analyzing',
        message: '正在分析文章内容...',
        percentage: 10
      })

      // 构建Prompt
      const prompt = this.buildPrompt(request)
      console.log('[火花分镜] Prompt已生成')
      console.log('================== Prompt开始 ==================')
      console.log(prompt)
      console.log('================== Prompt结束 ==================')

      // 阶段2: 准备AI请求 (20%)
      onProgress?.({
        phase: 'analyzing',
        message: '准备AI生成请求...',
        percentage: 20
      })

      // 阶段3: 开始AI生成 (30%)
      onProgress?.({
        phase: 'generating',
        message: '正在生成分镜场景...',
        percentage: 30
      })

      // 启动模拟进度更新(从30%到85%)
      const progressInterval = this.startProgressSimulation(onProgress, 30, 85, 30000) // 30秒内从30%增长到85%

      try {
        // 调用AI生成
        const aiResult = await this.aiService.generateText({
          prompt: prompt,
          maxTokens: this.calculateMaxTokens(request.config.targetDuration),
          temperature: 0.7
        })

        // 停止模拟进度
        clearInterval(progressInterval)

        if (!aiResult.ok) {
          console.error('[火花分镜] AI调用失败:', aiResult.error)
          return aiResult
        }

        console.log('[火花分镜] AI返回内容:')
        console.log('================== AI返回开始 ==================')
        console.log(aiResult.data)
        console.log('================== AI返回结束 ==================')

        // 阶段4: AI响应已接收 (90%)
        onProgress?.({
          phase: 'completing',
          message: '正在解析分镜数据...',
          percentage: 90
        })

        // 解析场景数据
        const scenes = this.parseScenes(aiResult.data, request.config)

        // 阶段5: 构建数据结构 (95%)
        onProgress?.({
          phase: 'completing',
          message: '正在构建分镜结构...',
          percentage: 95
        })

        // 构建StoryboardData
        const storyboardData: StoryboardData = {
          scenes,
          totalDuration: request.config.targetDuration,
          videoFormat: {
            aspectRatio: AspectRatio.STANDARD,
            resolution: VideoResolution.FULL_HD,
            frameRate: 25
          },
          projectAssets: {
            characters: [],
            props: [],
            locations: [],
            music: [],
            soundEffects: []
          }
        }

        // 阶段6: 完成 (100%)
        onProgress?.({
          phase: 'completing',
          message: '分镜生成完成',
          percentage: 100
        })

        console.log('[火花分镜] 分镜生成成功', {
          sceneCount: scenes.length,
          totalDuration: storyboardData.totalDuration
        })

        return {
          ok: true,
          data: storyboardData
        }
      } catch (aiError) {
        // 确保停止模拟进度
        clearInterval(progressInterval)
        throw aiError
      }
    } catch (error) {
      console.error('[火花分镜] 生成失败:', error)
      return {
        ok: false,
        error: {
          code: AIErrorCode.UNKNOWN,
          message: error instanceof Error ? error.message : '未知错误'
        }
      }
    }
  }

  /**
   * 启动模拟进度更新
   * 在AI请求期间平滑增长进度条
   */
  private startProgressSimulation(
    onProgress: ((progress: GenerationProgress) => void) | undefined,
    startPercentage: number,
    endPercentage: number,
    duration: number
  ): NodeJS.Timeout {
    if (!onProgress) {
      return setTimeout(() => {}, 0) // 返回空定时器
    }

    let currentPercentage = startPercentage
    const increment = (endPercentage - startPercentage) / (duration / 500) // 每500ms更新一次

    const interval = setInterval(() => {
      currentPercentage += increment

      // 不超过目标百分比
      if (currentPercentage >= endPercentage) {
        currentPercentage = endPercentage
        clearInterval(interval)
      }

      onProgress({
        phase: 'generating',
        message: 'AI正在创作分镜内容...',
        percentage: Math.floor(currentPercentage)
      })
    }, 500)

    return interval
  }

  /**
   * 构建AI生成Prompt
   */
  private buildPrompt(request: StoryboardGenerationRequest): string {
    const { config, articlePlainText } = request
    const styleLabel = VIDEO_STYLE_LABELS[config.videoStyle]
    const styleDescription = this.getStyleDescription(config.videoStyle)
    const suggestedSceneCount = this.calculateSuggestedSceneCount(
      config.targetDuration,
      config.videoStyle
    )

    return `你是专业的视频分镜师，请根据以下文章内容生成视频分镜脚本。

【文章内容】
${articlePlainText}

【视频要求】
- 总时长: ${config.targetDuration}秒
- 视频风格: ${styleLabel}（${styleDescription}）

【生成要求】
1. 场景划分:
   - 根据文章内容自然分段，每段对应一个场景
   - 建议场景数量: ${suggestedSceneCount}个场景
   - 每个场景要有明确的视觉焦点和叙事功能

2. 镜头参数:
   - shotType（景别）: wide（远景）/ medium（中景）/ close_up（近景）/ extreme_close（特写）
   - angle（角度）: eye_level（平视）/ high_angle（俯拍）/ low_angle（仰拍）
   - movement（运动）: static（静止）/ pan_left（左摇）/ pan_right（右摇）/ zoom_in（推镜）/ zoom_out（拉镜）/ tracking（跟拍）
   - duration（时长）: 根据总时长${config.targetDuration}秒合理分配

3. 场景描述:
   - title: 简洁有力的场景标题（5-15字）
   - description: 详细的场景描述，包含拍摄主体、动作、环境（20-50字）

【输出格式】
请严格按照以下JSON格式输出，不要添加任何其他内容:
{
  "scenes": [
    {
      "title": "场景标题",
      "description": "详细的场景描述，包含拍摄主体、动作、环境",
      "shotType": "medium",
      "angle": "eye_level",
      "movement": "static",
      "duration": 5,
      "order": 0
    }
  ]
}

注意:
- 只输出JSON格式，不要其他任何文字
- 所有场景时长之和应等于或接近${config.targetDuration}秒
- 根据"${styleLabel}"风格调整镜头类型和运动方式
- 确保JSON格式正确，可以被直接解析`
  }

  /**
   * 获取风格描述
   */
  private getStyleDescription(style: VideoStyle): string {
    switch (style) {
      case VideoStyle.DYNAMIC:
        return '多镜头切换，节奏明快，镜头运动丰富'
      case VideoStyle.STATIC:
        return '固定镜头为主，画面稳定，节奏舒缓'
      case VideoStyle.DOCUMENTARY:
        return '长镜头为主，自然纪实，注重细节'
      case VideoStyle.COMMERCIAL:
        return '精致构图，视觉冲击强，节奏紧凑'
    }
  }

  /**
   * 计算建议的场景数量
   */
  private calculateSuggestedSceneCount(duration: number, style: VideoStyle): number {
    // 根据风格确定平均场景时长
    let avgSceneDuration: number
    switch (style) {
      case VideoStyle.DYNAMIC:
        avgSceneDuration = 3 // 动态风格场景更短
        break
      case VideoStyle.STATIC:
        avgSceneDuration = 8 // 静态风格场景更长
        break
      case VideoStyle.DOCUMENTARY:
        avgSceneDuration = 10 // 纪录片风格场景最长
        break
      case VideoStyle.COMMERCIAL:
        avgSceneDuration = 4 // 广告风格场景较短
        break
    }

    const sceneCount = Math.round(duration / avgSceneDuration)
    // 限制场景数量在合理范围内
    return Math.max(3, Math.min(20, sceneCount))
  }

  /**
   * 计算最大Token数
   */
  private calculateMaxTokens(duration: number): number {
    // 根据时长估算需要的token数
    // 每个场景约需要150个token，加上额外开销
    const suggestedScenes = Math.ceil(duration / 5)
    return Math.min(2000, 300 + suggestedScenes * 150)
  }

  /**
   * 解析AI返回的场景数据
   */
  private parseScenes(
    aiResponse: string,
    config: SparkStoryboardConfig
  ): StoryboardScene[] {
    try {
      // 清理AI返回的内容，提取JSON部分
      const jsonMatch = aiResponse.match(/\{[\s\S]*\}/)
      if (!jsonMatch) {
        console.warn('[火花分镜] 无法找到JSON格式，使用降级方案')
        return this.createFallbackScenes(config)
      }

      const jsonStr = jsonMatch[0]
      const parsed: AIScenesResponse = JSON.parse(jsonStr)

      if (!parsed.scenes || !Array.isArray(parsed.scenes)) {
        console.warn('[火花分镜] JSON格式不正确，使用降级方案')
        return this.createFallbackScenes(config)
      }

      // 转换为StoryboardScene格式
      const scenes: StoryboardScene[] = parsed.scenes.map((aiScene, index) => {
        return {
          id: generateId(),
          title: aiScene.title || `场景 ${index + 1}`,
          description: aiScene.description || '',
          order: index,
          shot: {
            type: this.parseShotType(aiScene.shotType),
            angle: this.parseCameraAngle(aiScene.angle),
            movement: aiScene.movement ? this.parseCameraMovement(aiScene.movement) : undefined
          },
          timing: {
            duration: aiScene.duration || 5
          },
          sceneLocation: {
            name: '',
            type: LocationType.INTERIOR,
            lighting: LightingCondition.NATURAL_DAY
          },
          elements: {
            characters: [],
            props: []
          },
          audioElements: {},
          visual: {},
          production: {
            priority: 'normal',
            complexity: 'simple',
            requiredCrew: []
          },
          attachments: {}
        }
      })

      // 调整时长确保总和接近目标时长
      this.adjustSceneDurations(scenes, config.targetDuration)

      return scenes
    } catch (error) {
      console.error('[火花分镜] JSON解析失败:', error)
      return this.createFallbackScenes(config)
    }
  }

  /**
   * 调整场景时长，确保总和接近目标时长
   */
  private adjustSceneDurations(scenes: StoryboardScene[], targetDuration: number): void {
    const currentTotal = scenes.reduce((sum, scene) => sum + scene.timing.duration, 0)

    if (currentTotal === 0) {
      // 如果所有场景时长都是0，平均分配
      const avgDuration = targetDuration / scenes.length
      scenes.forEach(scene => {
        scene.timing.duration = Math.round(avgDuration)
      })
      return
    }

    // 按比例调整
    const ratio = targetDuration / currentTotal
    scenes.forEach(scene => {
      scene.timing.duration = Math.round(scene.timing.duration * ratio)
    })

    // 修正舍入误差
    const newTotal = scenes.reduce((sum, scene) => sum + scene.timing.duration, 0)
    const diff = targetDuration - newTotal
    if (diff !== 0 && scenes.length > 0) {
      scenes[0].timing.duration += diff
    }
  }

  /**
   * 创建降级场景（当AI生成失败时）
   */
  private createFallbackScenes(config: SparkStoryboardConfig): StoryboardScene[] {
    const sceneCount = 3 // 默认3个场景
    const sceneDuration = Math.round(config.targetDuration / sceneCount)

    const scenes: StoryboardScene[] = [
      {
        id: generateId(),
        title: '开场引入',
        description: '介绍主题和背景信息',
        order: 0,
        shot: {
          type: ShotType.WIDE,
          angle: CameraAngle.EYE_LEVEL
        },
        timing: {
          duration: sceneDuration
        },
        sceneLocation: {
          name: '',
          type: LocationType.INTERIOR,
          lighting: LightingCondition.NATURAL_DAY
        },
        elements: {
          characters: [],
          props: []
        },
        audioElements: {},
        visual: {},
        production: {
          priority: 'normal',
          complexity: 'simple',
          requiredCrew: []
        },
        attachments: {}
      },
      {
        id: generateId(),
        title: '主体内容',
        description: '详细展开核心内容',
        order: 1,
        shot: {
          type: ShotType.MEDIUM,
          angle: CameraAngle.EYE_LEVEL
        },
        timing: {
          duration: sceneDuration
        },
        sceneLocation: {
          name: '',
          type: LocationType.INTERIOR,
          lighting: LightingCondition.NATURAL_DAY
        },
        elements: {
          characters: [],
          props: []
        },
        audioElements: {},
        visual: {},
        production: {
          priority: 'normal',
          complexity: 'simple',
          requiredCrew: []
        },
        attachments: {}
      },
      {
        id: generateId(),
        title: '总结收尾',
        description: '总结要点并结束',
        order: 2,
        shot: {
          type: ShotType.CLOSE_UP,
          angle: CameraAngle.EYE_LEVEL
        },
        timing: {
          duration: config.targetDuration - sceneDuration * 2 // 剩余时间
        },
        sceneLocation: {
          name: '',
          type: LocationType.INTERIOR,
          lighting: LightingCondition.NATURAL_DAY
        },
        elements: {
          characters: [],
          props: []
        },
        audioElements: {},
        visual: {},
        production: {
          priority: 'normal',
          complexity: 'simple',
          requiredCrew: []
        },
        attachments: {}
      }
    ]

    return scenes
  }

  /**
   * 解析景别类型
   */
  private parseShotType(shotType: string): ShotType {
    const typeMap: Record<string, ShotType> = {
      'extreme_wide': ShotType.EXTREME_WIDE,
      'wide': ShotType.WIDE,
      'medium_wide': ShotType.MEDIUM_WIDE,
      'medium': ShotType.MEDIUM,
      'medium_close': ShotType.MEDIUM_CLOSE,
      'close_up': ShotType.CLOSE_UP,
      'extreme_close': ShotType.EXTREME_CLOSE,
      'detail': ShotType.DETAIL
    }
    return typeMap[shotType] || ShotType.MEDIUM
  }

  /**
   * 解析拍摄角度
   */
  private parseCameraAngle(angle: string): CameraAngle {
    const angleMap: Record<string, CameraAngle> = {
      'eye_level': CameraAngle.EYE_LEVEL,
      'high_angle': CameraAngle.HIGH_ANGLE,
      'low_angle': CameraAngle.LOW_ANGLE,
      'bird_eye': CameraAngle.BIRD_EYE,
      'worm_eye': CameraAngle.WORM_EYE,
      'dutch_angle': CameraAngle.DUTCH_ANGLE,
      'over_shoulder': CameraAngle.OVER_SHOULDER
    }
    return angleMap[angle] || CameraAngle.EYE_LEVEL
  }

  /**
   * 解析镜头运动
   */
  private parseCameraMovement(movement: string): CameraMovement {
    const movementMap: Record<string, CameraMovement> = {
      'static': CameraMovement.STATIC,
      'pan_left': CameraMovement.PAN_LEFT,
      'pan_right': CameraMovement.PAN_RIGHT,
      'tilt_up': CameraMovement.TILT_UP,
      'tilt_down': CameraMovement.TILT_DOWN,
      'zoom_in': CameraMovement.ZOOM_IN,
      'zoom_out': CameraMovement.ZOOM_OUT,
      'dolly_in': CameraMovement.DOLLY_IN,
      'dolly_out': CameraMovement.DOLLY_OUT,
      'tracking': CameraMovement.TRACKING,
      'handheld': CameraMovement.HANDHELD,
      'drone': CameraMovement.DRONE,
      'crane': CameraMovement.CRANE
    }
    return movementMap[movement] || CameraMovement.STATIC
  }
}
